package me.kagami.gsp.service;


import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTypesUtil;
import me.kagami.gsp.util.PsiClassUtils;
import me.kagami.gsp.util.PsiToolUtils;

import java.util.List;

public class GenerateDefaultForOneMethodDeclare extends GenerateDefaultForOneMethodTemplate {
    /**
     * 生成需要设置初始值字符串，A<B> 如果B不是基本类，那么需要生成一个 B b = new B(); 的字符串
     */
    public void generateMethodArgsDeclareStatement() {
        PsiParameter[] parameters = generateContext.getMethod().getParameterList().getParameters();
        //获取类上的泛型，这里得到的是T
        PsiTypeParameter[] typeParameters = PsiTypesUtil.getClassType(generateContext.getPsiClass()).resolve().getTypeParameters();
        //这里会获取具体的泛型 String
        Parameters outerParameters = PsiToolUtils.extractParamInfo(generateContext.getLocalVariable().getType());

        for (PsiParameter parameter : parameters) {
            //这里得到的是T
            String classType = parameter.getType().getCanonicalText();
            //针对泛型变量和非泛型变量需要分别处理，泛型变量需要将泛型T，R之类的声明，映射成具体的类型
            if (isGenerics(parameter, typeParameters)) {
                for (int i = 0; i < typeParameters.length; i++) {
                    //判断set方法的入参是否与类上的泛型一样，如果一样，则新生成赋值字符串
                    if (typeParameters[i].getName().equals(classType)) {
                        //这里获取的是T对应的具体类型
                        RealParam realParam = outerParameters.getParams().get(i);
                        //如果具体类型是基本类型，那么不需要生成一个赋值字符串
                        String basicAndCommonType = typeGeneratedMap.get(realParam.getRealPackage());
                        if (basicAndCommonType != null) {
                            continue;
                        }
                        //这里只兼容两层的泛型 ClassA<List<ClassB>>或者 ClassA<ClassB> 。两层以上应该是不行的ClassA<ClassB<List<ClassC>>>
                        Parameters innerParameters = PsiToolUtils.extractParamInfo(realParam.getRealPackage(), realParam.getRealName());
                        innerHandle(parameter, innerParameters);
                        break;
                    }
                }
            } else {
                //如果具体类型是基本类型，那么不需要生成一个赋值字符串
                String basicAndCommonType = typeGeneratedMap.get(parameter.getType().getCanonicalText());
                if (basicAndCommonType != null) {
                    continue;
                }
                //这里只兼容两层的泛型 ClassA<List<ClassB>>或者 ClassA<ClassB> 。两层以上应该是不行的ClassA<ClassB<List<ClassC>>>
                Parameters innerParameters = PsiToolUtils.extractParamInfo(parameter.getType());
                innerHandle(parameter, innerParameters);
            }
        }
    }

    private void innerHandle(PsiParameter parameter, Parameters innerParameters) {
        StringBuilder innerSb = new StringBuilder();
        //泛型类型的处理
        if (innerParameters.getCollectName() != null) {
            String defaultImpl = defaultCollections.get(innerParameters.getCollectName());

            innerSb.append(generateContext.getSplitText());
            innerSb.append(innerParameters.getPresentableText() + " " + parameter.getName() + " = ");
            if (defaultImpl != null) {
                appendCollectNotEmpty(innerSb, innerParameters, defaultImpl, generateContext.getNewImportList());
                generateContext.getNewImportList().add(defaultImportMap.get(innerParameters.getCollectName()));
            } else {
                appendCollectNotEmpty(innerSb, innerParameters, innerParameters.getCollectName(), generateContext.getNewImportList());
                generateContext.getNewImportList().add(innerParameters.getCollectPackage());
            }
            innerSb.append(";");
            innerSb.append(generateContext.getSplitText());
        } else {
            //普通类型的处理
            String realPackage = innerParameters.getParams().get(0).getRealPackage();
            String s = defaultPackageValues.get(realPackage);
            final PsiClass psiClassOfParameter = PsiTypesUtil.getPsiClass(parameter.getType());
            //不能是基本类型，不能是枚举s
            if (s == null && !(psiClassOfParameter != null && psiClassOfParameter.isEnum())) {
                String realName = innerParameters.getParams().get(0).getRealName();

                innerSb.append(generateContext.getSplitText());
                innerSb.append(realName + " " + parameter.getName() + " = new " + realName + "();");
                PsiClass aClass = JavaPsiFacade.getInstance(generateContext.getProject()).findClass(innerParameters.getParams().get(0).getRealPackage(), GlobalSearchScope.allScope(generateContext.getProject()));
                List<PsiMethod> tempM = PsiClassUtils.extractSetMethods(aClass);
                StringBuilder tempSb = new StringBuilder();
                for (PsiMethod m : tempM) {
                    tempSb.append(generateContext.getSplitText());
                    GenerateDefaultForOneMethodCommon temp = new GenerateDefaultForOneMethodCommon();
                    temp.setSimpleValue(this.isSimpleValue());
                    temp.setBuilder(tempSb);
                    temp.setGenerateName(parameter.getName());
                    temp.setMethod(m);
                    temp.setNewImportList(generateContext.getNewImportList());
                    temp.generateDefaultForOneMethod();
                }
                innerSb.append(tempSb);
                innerSb.append(generateContext.getSplitText());
            }
            generateContext.getNewImportList().add(realPackage);
        }
        generateContext.getBuilder().append(innerSb);
    }

    private boolean isGenerics(PsiParameter parameter, PsiTypeParameter[] typeParameters) {
        String classType = parameter.getType().getCanonicalText();
        for (int i = 0; i < typeParameters.length; i++) {
            //判断set方法的入参是否与类上的泛型一样，如果一样，则新生成赋值字符串
            if (typeParameters[i].getName().equals(classType)) {
                return true;
            }
        }
        return false;
    }

    private GenerateContext generateContext;

    public void setGenerateContext(GenerateContext generateContext) {
        this.generateContext = generateContext;
        this.generateName = generateContext.getLocalVariable().getName();
        this.newImportList = generateContext.getNewImportList();
        this.builder = generateContext.getBuilder();
        this.method = generateContext.getMethod();
        this.localVariable = generateContext.getLocalVariable();
    }

    protected void handle(PsiParameter parameter, Parameters paramInfo) {
        String classType = parameter.getType().getCanonicalText();
        PsiClass psiClass = PsiTypesUtil.getPsiClass(localVariable.getType());
        PsiTypeParameter[] typeParameters = PsiTypesUtil.getClassType(psiClass).resolve().getTypeParameters();
        Parameters outerParameters = PsiToolUtils.extractParamInfo(generateContext.getLocalVariable().getType());
        boolean isGenerics = false;
        //这段的目的是为了将类声明中的T 转换成相对应的具体泛型，如果是基本类型则赋初始值
        for (int i = 0; i < typeParameters.length; i++) {
            if (typeParameters[i].getName().equals(classType)) {
                RealParam realParam = outerParameters.getParams().get(i);
                handleBasicType(parameter, realParam.getRealPackage());
                isGenerics = true;
                break;
            }
        }
        //普通的类，也要判断基本类型
        if (!isGenerics) {
            handleBasicType(parameter, classType);
        }
    }

    private void handleBasicType(PsiParameter parameter, String classType) {
        String basicAndCommonType;
        if (isSimpleValue()) {
            basicAndCommonType = typeGeneratedSimpleValueMap.get(classType);
        } else {
            basicAndCommonType = typeGeneratedMap.get(classType);
        }

        if (basicAndCommonType != null) {
            builder.append(basicAndCommonType);
            String importType = typeGeneratedImport.get(classType);
            if (importType != null) {
                newImportList.add(importType);
            }
        } else {
            builder.append(parameter.getName());
        }
    }
}